/**
 * @file XMen_asn1.h
 * @brief ASN.1 encoding and decoding library for SM2 cryptography
 * This header file provides functions for ASN.1 DER encoding and decoding,
 * specifically designed for use with SM2 cryptographic operations.
 */

#ifndef LIB_ASN1_H
#define LIB_ASN1_H

#include <time.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>

#ifdef __cplusplus
extern "C" {
#endif

/**
 * @brief Maximum value for 32-bit signed integer
 */
#define INT_MAX   2147483647

/**
 * @brief OID nodes for PKIX
 */
#define oid_pkix 1, 3, 6, 1, 5, 5, 7

/**
 * @brief OID nodes for Private Enterprise
 */
#define oid_pe   oid_pkix, 1

/**
 * @brief OID nodes for Qualified Type
 */
#define oid_qt   oid_pkix, 2

/**
 * @brief OID nodes for Key Purpose
 */
#define oid_kp   oid_pkix, 3

/**
 * @brief OID nodes for Access Description
 */
#define oid_ad   oid_pkix, 48

/**
 * @brief OID nodes for RSA Data Security Inc.
 */
#define oid_rsadsi 1, 2, 840, 113549

/**
 * @brief OID nodes for PKCS
 */
#define oid_pkcs   oid_rsadsi, 1

/**
 * @brief OID nodes for PKCS#5
 */
#define oid_pkcs5  oid_pkcs, 5

/**
 * @brief OID nodes for X9.62
 */
#define oid_x9_62      1, 2, 840, 10045

/**
 * @brief OID nodes for Attribute Types
 */
#define oid_at         2, 5, 4

/**
 * @brief OID nodes for Certificate Extensions
 */
#define oid_ce         2, 5, 29

/**
 * @brief OID nodes for SM2
 */
#define oid_sm         1, 2, 156, 10197

/**
 * @brief OID nodes for SM2 algorithms
 */
#define oid_sm_algors  oid_sm, 1

/**
 * @brief OID nodes for SM2 CMS
 */
#define oid_sm2_cms    oid_sm, 6, 1, 4, 2

/**
 * @brief Calculate number of nodes in OID array
 */
#define oid_cnt(nodes) (sizeof(nodes) / sizeof((nodes)[0]))

/**
 * @brief Get 16-bit unsigned integer from byte array (big endian)
 */
#define GETU16(p) \
((uint16_t)(p)[0] <<  8 | \
(uint16_t)(p)[1])

/**
 * @brief Get 32-bit unsigned integer from byte array (big endian)
 */
#define GETU32(p) \
((uint32_t)(p)[0] << 24 | \
(uint32_t)(p)[1] << 16 | \
(uint32_t)(p)[2] <<  8 | \
(uint32_t)(p)[3])

/**
 * @brief Get 64-bit unsigned integer from byte array (big endian)
 */
#define GETU64(p) \
((uint64_t)(p)[0] << 56 | \
(uint64_t)(p)[1] << 48 | \
(uint64_t)(p)[2] << 40 | \
(uint64_t)(p)[3] << 32 | \
(uint64_t)(p)[4] << 24 | \
(uint64_t)(p)[5] << 16 | \
(uint64_t)(p)[6] <<  8 | \
(uint64_t)(p)[7])

/**
 * @brief Put 16-bit unsigned integer to byte array (big endian)
 */
#define PUTU16(p,V) \
((p)[0] = (uint8_t)((V) >> 8), \
(p)[1] = (uint8_t)(V))

/**
 * @brief Put 32-bit unsigned integer to byte array (big endian)
 */
#define PUTU32(p,V) \
((p)[0] = (uint8_t)((V) >> 24), \
(p)[1] = (uint8_t)((V) >> 16), \
(p)[2] = (uint8_t)((V) >>  8), \
(p)[3] = (uint8_t)(V))

/**
 * @brief Put 64-bit unsigned integer to byte array (big endian)
 */
#define PUTU64(p,V) \
((p)[0] = (uint8_t)((V) >> 56), \
(p)[1] = (uint8_t)((V) >> 48), \
(p)[2] = (uint8_t)((V) >> 40), \
(p)[3] = (uint8_t)((V) >> 32), \
(p)[4] = (uint8_t)((V) >> 24), \
(p)[5] = (uint8_t)((V) >> 16), \
(p)[6] = (uint8_t)((V) >>  8), \
(p)[7] = (uint8_t)(V))

/**
 * @brief Get 16-bit unsigned integer from byte array (little endian)
 */
#define GETU16_LE(p) (*(const uint16_t *)(p))

/**
 * @brief Get 32-bit unsigned integer from byte array (little endian)
 */
#define GETU32_LE(p) (*(const uint32_t *)(p))

/**
 * @brief Get 64-bit unsigned integer from byte array (little endian)
 */
#define GETU64_LE(p) (*(const uint64_t *)(p))

/**
 * @brief Put 16-bit unsigned integer to byte array (little endian)
 */
#define PUTU16_LE(p,V) *(uint16_t *)(p) = (V)

/**
 * @brief Put 32-bit unsigned integer to byte array (little endian)
 */
#define PUTU32_LE(p,V) *(uint32_t *)(p) = (V)

/**
 * @brief Put 64-bit unsigned integer to byte array (little endian)
 */
#define PUTU64_LE(p,V) *(uint64_t *)(p) = (V)

/**
 * @brief Rotate 32-bit integer left
 */
#define ROL32(a,n)     (((a)<<(n))|(((a)&0xffffffff)>>(32-(n))))

/**
 * @brief Rotate 64-bit integer left
 */
#define ROL64(a,n) (((a)<<(n))|((a)>>(64-(n))))

/**
 * @brief Rotate 32-bit integer right
 */
#define ROR32(a,n)	ROL32((a),32-(n))

/**
 * @brief Rotate 64-bit integer right
 */
#define ROR64(a,n)	ROL64(a,64-n)

#define ASN1_TAG_UNIVERSAL		0x00
#define ASN1_TAG_APPLICATION		0x40
#define ASN1_TAG_CONTENT_SPECIFIC	0x80
#define ASN1_TAG_PRIVATE		0xC0
#define ASN1_TAG_PRIMITIVE		0x00
#define ASN1_TAG_CONSTRUCTED		0x20

#define ASN1_TAG_IMPLICIT(index)	(ASN1_TAG_CONTENT_SPECIFIC|(index))
#define ASN1_TAG_EXPLICIT(index)	ASN1_TAG_IMPLICIT(ASN1_TAG_CONSTRUCTED|(index))


#define ASN1_FMT_FULL	0x01

enum ASN1_TAG {
    ASN1_TAG_BOOLEAN = 1,
    ASN1_TAG_INTEGER = 2,
    ASN1_TAG_BIT_STRING = 3,
    ASN1_TAG_OCTET_STRING = 4,
    ASN1_TAG_NULL = 5,
    ASN1_TAG_OBJECT_IDENTIFIER = 6,
    ASN1_TAG_ObjectDescriptor = 7,
    ASN1_TAG_EXTERNAL = 8,
    ASN1_TAG_REAL = 9,
    ASN1_TAG_ENUMERATED = 10, ASN1_TAG_EMBEDDED = 11, ASN1_TAG_UTF8String = 12, ASN1_TAG_RELATIVE_OID = 13, ASN1_TAG_NumericString = 18, ASN1_TAG_PrintableString = 19, ASN1_TAG_TeletexString = 20, ASN1_TAG_VideotexString = 21, ASN1_TAG_IA5String = 22, ASN1_TAG_UTCTime = 23, ASN1_TAG_GeneralizedTime = 24, ASN1_TAG_GraphicString = 25, ASN1_TAG_VisibleString = 26, ASN1_TAG_GeneralString = 27, ASN1_TAG_UniversalString = 28, ASN1_TAG_CHARACTER_STRING = 29, ASN1_TAG_BMPString = 30, ASN1_TAG_SEQUENCE = 0x30,
    ASN1_TAG_SET = 0x31,
    ASN1_TAG_EXPLICIT = 0xa0,
};



int XMen_lib_asn1_sm2_len_to_der(uint32_t dlen, uint8_t** out, uint32_t* outlen);


int XMen_lib_asn1_sm2_length_from_der(uint32_t* dlen, const uint8_t** in, uint32_t* inlen);


/**
 * @brief Check if length value is zero
 * @param len Length value to check
 * @return 1 if length is zero, 0 otherwise
 */
int XMen_lib_asn1_sm2_length_is_zero(uint32_t len);


/**
 * @brief Compare two length values
 * @param len1 First length value
 * @param len2 Second length value
 * @return 1 if len1 <= len2, 0 otherwise
 */
int XMen_lib_asn1_sm2_length_le(uint32_t len1, uint32_t len2);


/**
 * @brief Convert raw data to DER encoding
 * @param d Input data buffer
 * @param dlen Length of input data
 * @param out Output buffer for DER encoding
 * @param outlen Length of output buffer
 * @return 0 on success, error code otherwise
 */
int XMen_lib_asn1_sm2_data_to_der(const uint8_t* d, uint32_t dlen, uint8_t** out, uint32_t* outlen);




/**
 * @brief Convert ASN.1 type and data to DER encoding
 * @param tag ASN.1 tag value
 * @param d Input data buffer
 * @param dlen Length of input data
 * @param out Output buffer for DER encoding
 * @param outlen Length of output buffer
 * @return 0 on success, error code otherwise
 */
int XMen_lib_asn1_sm2_type_to_der(int tag, const uint8_t* d, uint32_t dlen, uint8_t** out, uint32_t* outlen);


/**
 * @brief Parse ASN.1 type and data from DER encoding
 * @param tag Expected ASN.1 tag
 * @param d Output buffer for decoded data
 * @param dlen Length of decoded data
 * @param in Input DER buffer
 * @param inlen Length of input buffer
 * @return 0 on success, error code otherwise
 */
int XMen_lib_asn1_sm2_type_from_der(int tag, const uint8_t** d, uint32_t* dlen, const uint8_t** in, uint32_t* inlen);


/**
 * @brief Convert non-empty ASN.1 type and data to DER encoding
 * @param tag ASN.1 tag value
 * @param d Input data buffer
 * @param dlen Length of input data
 * @param out Output buffer for DER encoding
 * @param outlen Length of output buffer
 * @return 0 on success, error code otherwise
 */
int XMen_lib_asn1_sm2_nonempty_type_to_der(int tag, const uint8_t* d, uint32_t dlen, uint8_t** out, uint32_t* outlen);


/**
 * @brief Parse non-empty ASN.1 type and data from DER encoding
 * @param tag Expected ASN.1 tag
 * @param d Output buffer for decoded data
 * @param dlen Length of decoded data
 * @param in Input DER buffer
 * @param inlen Length of input buffer
 * @return 0 on success, error code otherwise
 */
int XMen_lib_asn1_sm2_nonempty_type_from_der(int tag, const uint8_t** d, uint32_t* dlen, const uint8_t** in, uint32_t* inlen);


/**
 * @brief Parse any ASN.1 type from DER encoding
 * @param tag Output parameter for detected tag
 * @param d Output buffer for decoded data
 * @param dlen Length of decoded data
 * @param in Input DER buffer
 * @param inlen Length of input buffer
 * @return 0 on success, error code otherwise
 */
int XMen_lib_asn1_sm2_any_type_from_der(int* tag, const uint8_t** d, uint32_t* dlen, const uint8_t** in, uint32_t* inlen);


/**
 * @brief Convert any ASN.1 data to DER encoding
 * @param a Input ASN.1 data buffer
 * @param alen Length of input data
 * @param out Output buffer for DER encoding
 * @param outlen Length of output buffer
 * @return 0 on success, error code otherwise
 */
int XMen_lib_asn1_sm2_any_to_der(const uint8_t* a, uint32_t alen, uint8_t** out, uint32_t* outlen);


/**
 * @brief Parse any ASN.1 data from DER encoding
 * @param a Output buffer for decoded data
 * @param alen Length of decoded data
 * @param in Input DER buffer
 * @param inlen Length of input buffer
 * @return 0 on success, error code otherwise
 */
int XMen_lib_asn1_sm2_any_from_der(const uint8_t** a, uint32_t* alen, const uint8_t** in, uint32_t* inlen);

/**
 * @brief Boolean values for ASN.1 encoding
 */
#define ASN1_TRUE  0xff
#define ASN1_FALSE 0x00



int XMen_lib_asn1_sm2_integer_to_der_ex(int tag, const uint8_t* d, uint32_t dlen, uint8_t** out, uint32_t* outlen);


int XMen_lib_asn1_sm2_integer_from_der_ex(int tag, const uint8_t** d, uint32_t* dlen, const uint8_t** in, uint32_t* inlen);


#define XMen_lib_asn1_sm2_integer_to_der(d, dlen, out, outlen) \
XMen_lib_asn1_sm2_integer_to_der_ex(ASN1_TAG_INTEGER, d, dlen, out, outlen)


#define XMen_lib_asn1_sm2_integer_from_der(d, dlen, in, inlen) \
XMen_lib_asn1_sm2_integer_from_der_ex(ASN1_TAG_INTEGER, d, dlen, in, inlen)


#define XMen_lib_asn1_sm2_implicit_integer_to_der(i, d, dlen, out, outlen) \
XMen_lib_asn1_sm2_integer_to_der_ex(ASN1_TAG_IMPLICIT(i), d, dlen, out, outlen)


#define XMen_lib_asn1_sm2_implicit_integer_from_der(i, d, dlen, in, inlen) \
XMen_lib_asn1_sm2_integer_from_der_ex(ASN1_TAG_IMPLICIT(i), d, dlen, in, inlen)


int XMen_lib_asn1_sm2_int_from_der_ex(int tag, int* val, const uint8_t** in, uint32_t* inlen);


#define XMen_lib_asn1_sm2_int_from_der(val, in, inlen) \
XMen_lib_asn1_sm2_int_from_der_ex(ASN1_TAG_INTEGER, val, in, inlen)


#define XMen_lib_asn1_sm2_implicit_int_from_der(i, val, in, inlen) \
XMen_lib_asn1_sm2_int_from_der_ex(ASN1_TAG_IMPLICIT(i), val, in, inlen)


int XMen_lib_asn1_sm2_bit_string_to_der_ex(int tag, const uint8_t* d, uint32_t nbits, uint8_t** out, uint32_t* outlen);


int XMen_lib_asn1_sm2_bit_string_from_der_ex(int tag, const uint8_t** d, uint32_t* nbits, const uint8_t** in, uint32_t* inlen);


/**
 * @brief Convert bit string to DER encoding with BIT STRING tag
 * Wrapper macro for bit_string_to_der_ex with ASN1_TAG_BIT_STRING
 */
#define XMen_lib_asn1_sm2_bit_string_to_der(d, nbits, out, outlen) \
XMen_lib_asn1_sm2_bit_string_to_der_ex(ASN1_TAG_BIT_STRING, d, nbits, out, outlen)

/**
 * @brief Parse bit string from DER encoding with BIT STRING tag
 * Wrapper macro for bit_string_from_der_ex with ASN1_TAG_BIT_STRING
 */
#define XMen_lib_asn1_sm2_bit_string_from_der(d, nbits, in, inlen) \
XMen_lib_asn1_sm2_bit_string_from_der_ex(ASN1_TAG_BIT_STRING, d, nbits, in, inlen)

/**
 * @brief Convert bit string to DER encoding with implicit tag
 * Wrapper macro for bit_string_to_der_ex with implicit tag
 */
#define XMen_lib_asn1_sm2_implicit_bit_string_to_der(i, d, nbits, out, outlen) \
XMen_lib_asn1_sm2_bit_string_to_der_ex(ASN1_TAG_IMPLICIT(i), d, nbits, out, outlen)

/**
 * @brief Parse bit string from DER encoding with implicit tag
 * Wrapper macro for bit_string_from_der_ex with implicit tag
 */
#define XMen_lib_asn1_sm2_implicit_bit_string_from_der(i, d, nbits, in, inlen) \
XMen_lib_asn1_sm2_bit_string_from_der_ex(ASN1_TAG_IMPLICIT(i), d, nbits, in, inlen)

/**
 * @brief Convert bit octets to DER encoding with explicit tag
 * @param tag ASN.1 tag value
 * @param d Input octet buffer
 * @param dlen Length of input buffer in octets
 * @param out Output buffer for DER encoding
 * @param outlen Length of output buffer
 * @return 0 on success, error code otherwise
 */
int XMen_lib_asn1_sm2_bit_octets_to_der_ex(int tag, const uint8_t* d, uint32_t dlen, uint8_t** out, uint32_t* outlen);

/**
 * @brief Parse bit octets from DER encoding with explicit tag
 * @param tag Expected ASN.1 tag
 * @param d Output buffer for decoded octets
 * @param dlen Length of decoded octets
 * @param in Input DER buffer
 * @param inlen Length of input buffer
 * @return 0 on success, error code otherwise
 */
int XMen_lib_asn1_sm2_bit_octets_from_der_ex(int tag, const uint8_t** d, uint32_t* dlen, const uint8_t** in, uint32_t* inlen);

/**
 * @brief Convert bit octets to DER encoding with BIT STRING tag
 * Wrapper macro for bit_octets_to_der_ex with ASN1_TAG_BIT_STRING
 */
#define XMen_lib_asn1_sm2_bit_octets_to_der(d, dlen, out, outlen) \
XMen_lib_asn1_sm2_bit_octets_to_der_ex(ASN1_TAG_BIT_STRING, d, dlen, out, outlen)

/**
 * @brief Parse bit octets from DER encoding with BIT STRING tag
 * Wrapper macro for bit_octets_from_der_ex with ASN1_TAG_BIT_STRING
 */
#define XMen_lib_asn1_sm2_bit_octets_from_der(d, dlen, in, inlen) \
XMen_lib_asn1_sm2_bit_octets_from_der_ex(ASN1_TAG_BIT_STRING, d, dlen, in, inlen)

/**
 * @brief Convert bit octets to DER encoding with implicit tag
 * Wrapper macro for bit_octets_to_der_ex with implicit tag
 */
#define XMen_lib_asn1_sm2_implicit_bit_octets_to_der(i, d, dlen, out, outlen) \
XMen_lib_asn1_sm2_bit_octets_to_der_ex(ASN1_TAG_IMPLICIT(i), d, dlen, out, outlen)

/**
 * @brief Parse bit octets from DER encoding with implicit tag
 * Wrapper macro for bit_octets_from_der_ex with implicit tag
 */
#define XMen_lib_asn1_sm2_implicit_bit_octets_from_der(i, d, dlen, in, inlen) \
XMen_lib_asn1_sm2_bit_octets_from_der_ex(ASN1_TAG_IMPLICIT(i), d, dlen, in, inlen)

/**
 * @brief Convert bits to DER encoding with explicit tag
 * @param tag ASN.1 tag value
 * @param bits Integer representing bit flags
 * @param out Output buffer for DER encoding
 * @param outlen Length of output buffer
 * @return 0 on success, error code otherwise
 */
int XMen_lib_asn1_sm2_bits_to_der_ex(int tag, int bits, uint8_t** out, uint32_t* outlen);

/**
 * @brief Parse bits from DER encoding with explicit tag
 * @param tag Expected ASN.1 tag
 * @param bits Output parameter for decoded bit flags
 * @param in Input DER buffer
 * @param inlen Length of input buffer
 * @return 0 on success, error code otherwise
 */
int XMen_lib_asn1_sm2_bits_from_der_ex(int tag, int* bits, const uint8_t** in, uint32_t* inlen);

/**
 * @brief Convert bits to DER encoding with BIT STRING tag
 * Wrapper macro for bits_to_der_ex with ASN1_TAG_BIT_STRING
 */
#define XMen_lib_asn1_sm2_bits_to_der(bits, out, outlen) \
XMen_lib_asn1_sm2_bits_to_der_ex(ASN1_TAG_BIT_STRING, bits, out, outlen)

/**
 * @brief Parse bits from DER encoding with BIT STRING tag
 * Wrapper macro for bits_from_der_ex with ASN1_TAG_BIT_STRING
 */
#define XMen_lib_asn1_sm2_bits_from_der(bits, in, inlen) \
XMen_lib_asn1_sm2_bits_from_der_ex(ASN1_TAG_BIT_STRING, bits, in, inlen)

/**
 * @brief Convert octet string to DER encoding with explicit tag
 * Wrapper macro for type_to_der with specified tag
 */
#define XMen_lib_asn1_sm2_octet_string_to_der_ex(tag, d, dlen, out, outlen) \
XMen_lib_asn1_sm2_type_to_der(tag, d, dlen, out, outlen)

/**
 * @brief Parse octet string from DER encoding with explicit tag
 * Wrapper macro for type_from_der with specified tag
 */
#define XMen_lib_asn1_sm2_octet_string_from_der_ex(tag, d, dlen, in, inlen) \
XMen_lib_asn1_sm2_type_from_der(tag, d, dlen, in, inlen)

#define XMen_lib_asn1_sm2_octet_string_to_der(d, dlen, out, outlen) \
XMen_lib_asn1_sm2_type_to_der(ASN1_TAG_OCTET_STRING, d, dlen, out, outlen)


#define XMen_lib_asn1_sm2_octet_string_from_der(d, dlen, in, inlen) \
XMen_lib_asn1_sm2_type_from_der(ASN1_TAG_OCTET_STRING, d, dlen, in, inlen)


#define XMen_lib_asn1_sm2_implicit_octet_string_to_der(i, d, dlen, out, outlen) \
XMen_lib_asn1_sm2_type_to_der(ASN1_TAG_IMPLICIT(i), d, dlen, out, outlen)


#define XMen_lib_asn1_sm2_implicit_octet_string_from_der(i, d, dlen, in, inlen) \
XMen_lib_asn1_sm2_type_from_der(ASN1_TAG_IMPLICIT(i), d, dlen, in, inlen)

/**
 * @brief Minimum number of nodes in an OID
 */
#define ASN1_OID_MIN_NODES 2

/**
 * @brief Maximum number of nodes in an OID
 */
#define ASN1_OID_MAX_NODES 32

/**
 * @brief Minimum number of octets in encoded OID
 */
#define ASN1_OID_MIN_OCTETS 1

/**
 * @brief Maximum number of octets in encoded OID
 * Calculated as 1 + (max_nodes - 2) * 5
 */
#define ASN1_OID_MAX_OCTETS (1 + (ASN1_OID_MAX_NODES - 2) * 5)

/**
 * @brief Convert OID nodes to octet representation
 * @param nodes Array of OID node values
 * @param nodes_cnt Number of nodes
 * @param out Output buffer for encoded OID
 * @param outlen Length of output buffer
 * @return 0 on success, error code otherwise
 */
int XMen_lib_asn1_sm2_object_identifier_to_octets(const uint32_t* nodes, uint32_t nodes_cnt, uint8_t* out, uint32_t* outlen);

/**
 * @brief Parse OID from octet representation
 * @param nodes Output array for OID node values
 * @param nodes_cnt Number of nodes parsed
 * @param in Input buffer containing encoded OID
 * @param inlen Length of input buffer
 * @return 0 on success, error code otherwise
 */
int XMen_lib_asn1_sm2_object_identifier_from_octets(uint32_t* nodes, uint32_t* nodes_cnt, const uint8_t* in, uint32_t inlen);

/**
 * @brief Parse OID from DER encoding with explicit tag
 * @param tag Expected ASN.1 tag
 * @param nodes Output array for OID node values
 * @param nodes_cnt Number of nodes parsed
 * @param in Input DER buffer
 * @param inlen Length of input buffer
 * @return 0 on success, error code otherwise
 */
int XMen_lib_asn1_sm2_object_identifier_from_der_ex(int tag, uint32_t* nodes, uint32_t* nodes_cnt, const uint8_t** in, uint32_t* inlen);

/**
 * @brief Compare two OIDs for equality
 * @param a First OID node array
 * @param a_cnt Number of nodes in first OID
 * @param b Second OID node array
 * @param b_cnt Number of nodes in second OID
 * @return 1 if OIDs are equal, 0 otherwise
 */
int XMen_lib_asn1_sm2_object_identifier_equ(const uint32_t* a, uint32_t a_cnt, const uint32_t* b, uint32_t b_cnt);

/**
 * @brief Structure to hold OID information
 */
typedef struct {
    int oid;            /**< OID numeric identifier */
    char* name;         /**< OID name string */
    uint32_t* nodes;    /**< Array of OID node values */
    uint32_t nodes_cnt; /**< Number of nodes in OID */
    int flags;          /**< OID flags */
    char* description;  /**< OID description string */
} ASN1_OID_INFO;

/**
 * @brief Look up OID info by name
 * @param infos Array of OID info structures
 * @param count Number of entries in infos array
 * @param name Name to look up
 * @return Pointer to matching OID info or NULL if not found
 */
const ASN1_OID_INFO* XMen_lib_asn1_sm2_oid_info_from_name(const ASN1_OID_INFO* infos, uint32_t count, const char* name);

/**
 * @brief Look up OID info by OID value
 * @param infos Array of OID info structures
 * @param count Number of entries in infos array
 * @param oid OID value to look up
 * @return Pointer to matching OID info or NULL if not found
 */
const ASN1_OID_INFO* XMen_lib_asn1_sm2_oid_info_from_oid(const ASN1_OID_INFO* infos, uint32_t count, int oid);

/**
 * @brief Parse enumerated value from DER encoding with explicit tag
 * Wrapper macro for int_from_der_ex with specified tag
 */
#define XMen_lib_asn1_sm2_enumerated_from_der_ex(tag, val, in, inlen) \
XMen_lib_asn1_sm2_int_from_der_ex(tag, val, in, inlen)

/**
 * @brief Check if string is valid UTF-8 encoding
 * @param d Input string buffer
 * @param dlen Length of input string
 * @return 1 if valid UTF-8, 0 otherwise
 */
int XMen_lib_asn1_sm2_string_is_utf8_string(const char* d, uint32_t dlen);

/**
 * @brief Convert UTF-8 string to DER encoding with explicit tag
 * @param tag ASN.1 tag value
 * @param d Input UTF-8 string
 * @param dlen Length of input string
 * @param out Output buffer for DER encoding
 * @param outlen Length of output buffer
 * @return 0 on success, error code otherwise
 */
int XMen_lib_asn1_sm2_utf8_string_to_der_ex(int tag, const char* d, uint32_t dlen, uint8_t** out, uint32_t* outlen);

/**
 * @brief Parse UTF-8 string from DER encoding with explicit tag
 * @param tag Expected ASN.1 tag
 * @param d Output buffer for decoded UTF-8 string
 * @param dlen Length of decoded string
 * @param in Input DER buffer
 * @param inlen Length of input buffer
 * @return 0 on success, error code otherwise
 */
int XMen_lib_asn1_sm2_utf8_string_from_der_ex(int tag, const char** d, uint32_t* dlen, const uint8_t** in, uint32_t* inlen);

/**
 * @brief Check if string is valid IA5 encoding (ASCII)
 * @param d Input string buffer
 * @param dlen Length of input string
 * @return 1 if valid IA5, 0 otherwise
 */
int XMen_lib_asn1_sm2_string_is_ia5_string(const char* d, uint32_t dlen);

/**
 * @brief Convert IA5 string to DER encoding with explicit tag
 * @param tag ASN.1 tag value
 * @param d Input IA5 string
 * @param dlen Length of input string
 * @param out Output buffer for DER encoding
 * @param outlen Length of output buffer
 * @return 0 on success, error code otherwise
 */
int XMen_lib_asn1_sm2_ia5_string_to_der_ex(int tag, const char* d, uint32_t dlen, uint8_t** out, uint32_t* outlen);

/**
 * @brief Parse IA5 string from DER encoding with explicit tag
 * @param tag Expected ASN.1 tag
 * @param d Output buffer for decoded IA5 string
 * @param dlen Length of decoded string
 * @param in Input DER buffer
 * @param inlen Length of input buffer
 * @return 0 on success, error code otherwise
 */
int XMen_lib_asn1_sm2_ia5_string_from_der_ex(int tag, const char** d, uint32_t* dlen, const uint8_t** in, uint32_t* inlen);

/**
 * @brief Convert time value to string representation
 * @param utc_time 1 for UTC time format, 0 for Generalized time format
 * @param timestamp Unix timestamp to convert
 * @param str Output buffer for time string
 * @return 0 on success, error code otherwise
 */

#define XMen_lib_asn1_sm2_ia5_string_to_der(d, dlen, out, outlen) \
XMen_lib_asn1_sm2_ia5_string_to_der_ex(ASN1_TAG_IA5String, d, dlen, out, outlen)


#define XMen_lib_asn1_sm2_ia5_string_from_der(d, dlen, in, inlen) \
XMen_lib_asn1_sm2_ia5_string_from_der_ex(ASN1_TAG_IA5String, d, dlen, in, inlen)


#define XMen_lib_asn1_sm2_implicit_ia5_string_to_der(i, d, dlen, out, outlen) \
XMen_lib_asn1_sm2_ia5_string_to_der_ex(ASN1_TAG_IMPLICIT(i), d, dlen, out, outlen)


#define XMen_lib_asn1_sm2_implicit_ia5_string_from_der(i, d, dlen, in, inlen) \
XMen_lib_asn1_sm2_ia5_string_from_der_ex(ASN1_TAG_IMPLICIT(i), d, dlen, in, inlen)



#define ASN1_UTC_TIME_STRLEN        (sizeof("YYMMDDHHMMSSZ") - 1)


#define ASN1_GENERALIZED_TIME_STRLEN  (sizeof("YYYYMMDDHHMMSSZ") - 1)


#define ASN1_GENERALIZED_TIME_MAX_SIZE  (2 + ASN1_GENERALIZED_TIME_STRLEN)

int XMen_lib_asn1_sm2_time_to_str(int utc_time, time_t timestamp, char* str);

/**
 * @brief Parse time string to timestamp value
 * @param utc_time 1 for UTC time format, 0 for Generalized time format
 * @param timestamp Output parameter for parsed timestamp
 * @param str Input time string
 * @return 0 on success, error code otherwise
 */
int XMen_lib_asn1_sm2_time_from_str(int utc_time, time_t* timestamp, const char* str);

/**
 * @brief Convert UTC time to DER encoding with explicit tag
 * @param tag ASN.1 tag value
 * @param tv Unix timestamp to encode
 * @param out Output buffer for DER encoding
 * @param outlen Length of output buffer
 * @return 0 on success, error code otherwise
 */
int XMen_lib_asn1_sm2_utc_time_to_der_ex(int tag, time_t tv, uint8_t** out, uint32_t* outlen);


/**
 * @brief Convert UTC time to DER encoding with UTCTime tag
 * @param tv Unix timestamp to encode
 * @param out Output buffer for DER encoding
 * @param outlen Length of output buffer
 */
#define XMen_lib_asn1_sm2_utc_time_to_der(tv, out, outlen) \
XMen_lib_asn1_sm2_utc_time_to_der_ex(ASN1_TAG_UTCTime, tv, out, outlen)


/**
 * @brief Convert UTC time to DER encoding with implicit tag
 * @param i Implicit tag number
 * @param tv Unix timestamp to encode
 * @param out Output buffer for DER encoding
 * @param outlen Length of output buffer
 */
#define XMen_lib_asn1_sm2_implicit_utc_time_to_der(i, tv, out, outlen) \
XMen_lib_asn1_sm2_utc_time_to_der_ex(ASN1_TAG_IMPLICIT(i), tv, out, outlen)


/**
 * @brief Parse sequence from DER encoding
 * @param d Output buffer for sequence data
 * @param dlen Length of sequence data
 * @param in Input DER buffer
 * @param inlen Length of input buffer
 */
#define XMen_lib_asn1_sm2_sequence_from_der(d, dlen, in, inlen) \
XMen_lib_asn1_sm2_type_from_der(ASN1_TAG_SEQUENCE, d, dlen, in, inlen)


/**
 * @brief Convert sequence to DER encoding with implicit tag
 * @param i Implicit tag number
 * @param d Input sequence data
 * @param dlen Length of sequence data
 * @param out Output buffer for DER encoding
 * @param outlen Length of output buffer
 */
#define XMen_lib_asn1_sm2_implicit_sequence_to_der(i, d, dlen, out, outlen) \
XMen_lib_asn1_sm2_nonempty_type_to_der(ASN1_TAG_EXPLICIT(i), d, dlen, out, outlen)


/**
 * @brief Parse sequence from DER encoding with implicit tag
 * @param i Implicit tag number
 * @param d Output buffer for sequence data
 * @param dlen Length of sequence data
 * @param in Input DER buffer
 * @param inlen Length of input buffer
 */
#define XMen_lib_asn1_sm2_implicit_sequence_from_der(i, d, dlen, in, inlen) \
XMen_lib_asn1_sm2_nonempty_type_from_der(ASN1_TAG_EXPLICIT(i), d, dlen, in, inlen)


/**
 * @brief Convert sequence of items to DER encoding
 * @param d Input sequence data
 * @param dlen Length of sequence data
 * @param out Output buffer for DER encoding
 * @param outlen Length of output buffer
 */
#define XMen_lib_asn1_sm2_sequence_of_to_der(d, dlen, out, outlen) \
XMen_lib_asn1_sm2_nonempty_type_to_der(ASN1_TAG_SEQUENCE, d, dlen, out, outlen)


/**
 * @brief Parse sequence of items from DER encoding
 * @param d Output buffer for sequence data
 * @param dlen Length of sequence data
 * @param in Input DER buffer
 * @param inlen Length of input buffer
 */
#define XMen_lib_asn1_sm2_sequence_of_from_der(d, dlen, in, inlen) \
XMen_lib_asn1_sm2_nonempty_type_from_der(ASN1_TAG_SEQUENCE, d, dlen, in, inlen)


/**
 * @brief Generate DER encoding header
 * @param tag ASN.1 tag value
 * @param dlen Length of data
 * @param out Output buffer for header
 * @param outlen Length of output buffer
 * @return 1 on success, -1 on failure
 */
int XMen_lib_asn1_sm2_header_to_der(int tag, uint32_t dlen, uint8_t** out, uint32_t* outlen);

/**
 * @brief Generate DER encoding header for sequence
 * @param dlen Length of sequence data
 * @param out Output buffer for header
 * @param outlen Length of output buffer
 */
#define XMen_lib_asn1_sm2_sequence_header_to_der(dlen,out,outlen) XMen_lib_asn1_sm2_header_to_der(ASN1_TAG_SEQUENCE,dlen,out,outlen)

/**
 * @brief Get count of items of specified type in DER sequence/set
 * @param d Input DER buffer
 * @param dlen Length of input buffer
 * @param tag ASN.1 tag to count
 * @param cnt Output parameter for item count
 * @return 0 on success, error code otherwise
 */
int XMen_lib_asn1_sm2_types_get_count(const uint8_t* d, uint32_t dlen, int tag, uint32_t* cnt);

/**
 * @brief Get item by index from DER sequence/set
 * @param d Input DER buffer
 * @param dlen Length of input buffer
 * @param tag ASN.1 tag to match
 * @param index Zero-based index of item to retrieve
 * @param item_d Output buffer for item data
 * @param item_dlen Length of item data
 * @return 0 on success, error code otherwise
 */
int XMen_lib_asn1_sm2_types_get_item_by_index(const uint8_t* d, uint32_t dlen, int tag,
    int index, const uint8_t** item_d, uint32_t* item_dlen);

/**
 * @brief Check condition and return error if false
 * @param expr Condition to check
 * @return 0 if condition is true, error code otherwise
 */
int XMen_lib_asn1_sm2_check(int expr);

/**
 * @brief Check if memory buffer contains only zeros
 * @param buf Input buffer to check
 * @param len Length of buffer
 * @return 1 if buffer contains only zeros, 0 otherwise
 */
int mem_is_zero(const uint8_t* buf, uint32_t len);

/**
 * @brief Securely clear memory buffer
 * @param ptr Buffer to clear
 * @param len Length of buffer
 */
void secure_clear(void* ptr, size_t len);

/**
 * @brief XOR two memory buffers
 * @param r Output buffer for result
 * @param a First input buffer
 * @param b Second input buffer
 * @param len Length of buffers
 */
void XMen_lib_sm2_memxor(void* r, const void* a, const void* b, uint32_t len);

#if __cplusplus
}
#endif
#endif
